﻿using System;
using System.Collections.Generic;
using System.Data;

namespace Finance.Data.Entities
{
	public interface IRepayDebtDocuments : IDataBaseObjectCollection<IRepayDebtDocument>
	{
		IList<IRepayDebtDocument> RetrieveDocuments(DateTime date);
	}

	internal class RepayDebtDocuments : DataBaseObjectCollection<IRepayDebtDocument>, IRepayDebtDocuments
	{
		private const string SelectBase =
			"select document.*, documentsubtype.name as name " +
			"from repaydebtdocument as document left join documentsubtype on documentsubtype.documentsubtypeid = document.documentsubtypeid ";

		private const string InsertDocumentQuery =
			"insert into repaydebtdocument " +
			"(docdatetime, amount, typecode, documentsubtypeid, Description, contractorId, id, debtdocumentid, debtamount, rateamount) " +
			"values (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9)";

		private const string UpdateDocumentQuery =
			"update repaydebtdocument set amount = @p0, documentsubtypeid = @p1, description = @p2, contractorId = @p3, " +
			"docdatetime = @p4, debtdocumentid = @p5, debtamount = @p6, rateamount = @p7 where id = @p8";

		private const string RetrieveDocumentsQuery =
			SelectBase + 
			" where docdatetime >=@p0 and docdatetime < @p1 " +
			"order by docdatetime";

		private const string RetrieveItemQuery = SelectBase + " where document.id = @p0";

		public RepayDebtDocuments(FinanceDataBase dataBase) : base(dataBase, "repaydebtdocument")
		{
			IdColumn = "Id";
		}

		public override IRepayDebtDocument GetItem(Guid guid)
		{
			using (var dataReader = DataBase.Sql.ExecuteReader(RetrieveItemQuery, guid))
			{
				if (!dataReader.Read())
					throw new Exception("The item not found.");

				return ParseItem(dataReader);
			}
		}

		public override IRepayDebtDocument NewItem()
		{
			return new RepayDebtDocument(this, FinanceDataBase.Contractors);
		}

		public IList<IRepayDebtDocument> RetrieveDocuments(DateTime date)
		{
			var dateStart = new DateTime(date.Year, date.Month, date.Day);
			var dateEnd = dateStart.AddDays(1);

			using (var dataReader = DataBase.Sql.ExecuteReader(RetrieveDocumentsQuery, dateStart, dateEnd))
			{
				var documents = new List<IRepayDebtDocument>();
				while (dataReader.Read())
				{
					var document = ParseItem(dataReader);

					documents.Add(document);
				}
				return documents;
			}
		}


		protected override IRepayDebtDocument ParseItem(IDataRecord dataReader)
		{
			var document = new RepayDebtDocument(this, FinanceDataBase.Contractors)
			{
				Description = (string)dataReader["Description"],
				Id = (Guid)dataReader["id"],
				DocDate = (DateTime)dataReader["docdatetime"],
				Amount = (decimal)dataReader["amount"],
				SubTypeName = (string)dataReader["name"],
				DocumentType = (DocumentType)(int)dataReader["typecode"],
				DebtDocumentId = GetGuid(dataReader, "debtdocumentid"),
				ContractorId = GetGuid(dataReader, "contractorId"),
				DebtAmount = (decimal)dataReader["debtamount"],
				RateAmount = (decimal)dataReader["rateAmount"]
			};
			return document;
		}

		FinanceDataBase FinanceDataBase
		{
			get { return (FinanceDataBase)DataBase; }
		}

		protected override void Update(IRepayDebtDocument document)
		{
			var subTypeGuid = FinanceDataBase.DocumentSubTypes.CheckSubType(
				document.DocumentType, document.SubTypeName);

			try
			{
				using (var sql = ((FinanceDataBase)DataBase).OpenCommandProcessor())
				{
					sql.TransactionBegin();
					sql.ExecuteNonQuery(
						UpdateDocumentQuery,
						document.Amount,
						subTypeGuid,
						document.Description ?? "",
						document.ContractorId,
						document.DocDate,
						document.DebtDocumentId,
						document.DebtAmount,
						document.RateAmount,
						document.Id);
					sql.TransactionCommit();
				}
			}
			catch (Exception exception)
			{
				throw new Exception("Ошибка обновления данных документа в базе", exception);
			}
		}

		protected override void Insert(IRepayDebtDocument document)
		{
			var documentSubTypeId = FinanceDataBase.DocumentSubTypes.CheckSubType(
				document.DocumentType, document.SubTypeName);

			try
			{
				using (var sql = ((FinanceDataBase)DataBase).OpenCommandProcessor())
				{
					sql.TransactionBegin();
					document.Id = Guid.NewGuid();
					sql.ExecuteNonQuery(InsertDocumentQuery,
						document.DocDate,
						document.Amount,
						(int)document.DocumentType,
						documentSubTypeId,
						document.Description ?? "",
						document.ContractorId,
						document.Id,
						document.DebtDocumentId,
						document.DebtAmount,
						document.RateAmount);
					sql.TransactionCommit();
				}
			}
			catch (Exception exception)
			{
				throw new Exception("Ошибка сохранения данных документа в базе", exception);
			}
		}

		public override void Save(object item)
		{
			Save((RepayDebtDocument)item);
		}
	}
}
